#include "taskbusplatformfrm.h"
#include "ui_taskbusplatformfrm.h"
#include <QDebug>
#include <QFileDialog>
#include <QFileInfo>
#include <QProcess>
#include <QSettings>
#include <QThread>
#include <QDateTime>
#include <QMessageBox>
#include <QMap>
void taskBusPlatformFrm::load_modules(QStringList newfms)
{
	//QJSon
	struct mod_info{
		QString newfm;
		QString className;
		QByteArray bt;
	};
	QDir dirTaskbus(QCoreApplication::applicationDirPath());
	QMap<QString, mod_info> minfo;
	QStringList lstFailed,lstSucceed;
	int good = 0;
	foreach (QString newfm_ab, newfms)
	{
		QString newfm = dirTaskbus.relativeFilePath(newfm_ab);
		if (newfm.length()>newfm_ab.length())
			newfm = newfm_ab;
		emit showSplash(tr("Loading ")+newfm,Qt::AlignBottom,QColor(0,0,0));
		//首先试图找JSON文件.
		//We can provide a JSON file along with exe file.This approach
		//will significantly boost loading approach.
		QFileInfo infojs(newfm);
		QString abPath = infojs.absolutePath();
		QString abBName = infojs.completeBaseName();

		lstFailed << newfm;
		//Try JSON
		QString jsonfm = newfm+".json";
		QFile fjson(jsonfm), fjsonb(abPath+"/"+abBName+".json");
		QByteArray array ;
		if (fjson.open(QIODevice::ReadOnly))
		{
			array = fjson.readAll();
			fjson.close();
		}
		else if (fjsonb.open(QIODevice::ReadOnly))
		{
			array = fjsonb.readAll();
			fjsonb.close();
		}
		//找不到JSON，则调用命令行
		//Or, You can respond to the "--information" parameter and then
		//output the JSON information.
		else
		{
			QProcess proc;
			QFileInfo infocmd(newfm);
			proc.setProgram(infocmd.absoluteFilePath());
			proc.setWorkingDirectory(infocmd.absolutePath());
			proc.setArguments(QStringList()<<"--information");
			proc.start();
			array.append(proc.readAll());
			proc.waitForFinished(10000);
			array.append(proc.readAll());
			proc.kill();
		}
		int idx = array.indexOf('{');
		if (idx>0)
			array = array.mid(idx);
		idx = array.lastIndexOf("}");
		if (idx>0)
			array = array.left(idx+1);

		if (array.size())
		{
			taskModule mod;
			QByteArray bt = array;
			bool bOk = mod.initFromJson(bt,newfm);
			if (!bOk)
			{
				QString str = QString::fromLocal8Bit(array.data());
				bt = QByteArray::fromStdString(str.toStdString());
				bOk=mod.initFromJson(bt,newfm);
			}
			if (bOk)
			{
				mod_info info;
				QString className = mod.function_class(mod.function_firstname());
				info.bt = bt;
				info.newfm = newfm;
				info.className = className.trimmed();
				minfo[className+"|" + taskCell::pureName(mod.function_firstname())] = info;
				++good;
				lstSucceed<<lstFailed.last();
				lstFailed.pop_back();
			}

		}
		QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
	}
	QString loadres = tr("Load %1 Modules , %2 succeed:").arg(newfms.size()).arg(good);
	QStandardItem * itemMsg = new QStandardItem(loadres);
	if (good != newfms.size())
		itemMsg->setData(QColor(255,200,200),Qt::BackgroundRole);
	m_pMsgModel->appendRow(itemMsg);

	for (QString suc:lstSucceed)
	{
		QString msg = "\tLOADED:"+suc;
		QStandardItem * item = new QStandardItem(msg);
		m_pMsgModel->appendRow(item);
	}
	for (QString suc:lstFailed)
	{
		QString msg = "\tFAILED:"+suc;
		QStandardItem * item = new QStandardItem(msg);
		item->setData(QColor(255,200,200),Qt::BackgroundRole);
		m_pMsgModel->appendRow(item);
	}

	ui->dockWidget_message->show();

	QStringList keys = minfo.keys();
	foreach (QString k, keys)
	{
		QByteArray bt = minfo[k].bt;
		QString newfm = minfo[k].newfm;
		QString className = minfo[k].className;
		refModule()->initFromJson(bt,newfm);
		if (m_toolModules.contains(className)==false)
		{
			m_toolModules[className] = new taskModule(true,this);
			m_pClassModel->appendRow(new QStandardItem(className));
		}
		m_toolModules[className]->initFromJson(bt,newfm);

	}
}

/*!
 * \brief taskBusPlatformFrm::on_action_Load_Module_triggered
 * 用户选择一个EXE文件并导入 User choose a exe file to add into module list.
 */
void taskBusPlatformFrm::on_toolButton_addMod_clicked()
{
	QSettings settings(inifile(),QSettings::IniFormat);
	QString strLastModuleDir = settings.value("history/strLastModuleDir","./").toString();
#ifdef WIN32
	QStringList newfms = QFileDialog::getOpenFileNames(this,tr("load modules"),strLastModuleDir,
								 "exe files (*.exe);;All files(*.*)"
								 );
#else
	QStringList newfms = QFileDialog::getOpenFileNames(this,tr("load modules"),strLastModuleDir,
								 "exe files (* *.exe);;All files(*.*)"
								 );
#endif

	load_modules(newfms);
	if (newfms.size()>0)
	{
		QFileInfo info(newfms[0]);
		QDir dir(QCoreApplication::applicationDirPath());
		QString pts = info.absolutePath();
		QString strl = dir.relativeFilePath(pts);
		if (strl.length() < pts.length())
			pts = strl;
		settings.setValue("history/strLastModuleDir",pts);
	}
	//Save
	QString DefaultFile = QCoreApplication::applicationDirPath() + "/default_mods.text";
	QDir dir(QCoreApplication::applicationDirPath());
	QString mod_def = settings.value("current/mod_def",DefaultFile).toString();
	mod_def = dir.absoluteFilePath(mod_def);
	save_mod_def(mod_def);
	QString relp = dir.relativeFilePath(mod_def);
	if (relp.length()<=mod_def.length())
		mod_def = relp;
	settings.setValue("current/mod_def",mod_def);
}

void taskBusPlatformFrm::slot_showMsg(QStringList namestr,QByteArrayList strMessages)
{
	const int keepRows = 128;
	QString prefix = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss");
	int ct = 0;
	const int ctmsgs = namestr.size();
	auto ap = namestr.begin();
	auto av = strMessages.begin();
	for (; ap!=namestr.end() && av!=strMessages.end()
		 ;++ap,++av)
	{
		if (ctmsgs-ct<=keepRows)
			m_pMsgModel->appendRow(new QStandardItem(prefix+">"+*ap+QString::fromUtf8(*av)));
		++ct;
	}
	if (m_pMsgModel->rowCount()>keepRows)
		m_pMsgModel->removeRows(0,m_pMsgModel->rowCount()-keepRows);
	ui->listView_messages->scrollToBottom();

}


void taskBusPlatformFrm::save_mod_def(QString mod_file)
{
	const QSet<QString> & s = refModule()->full_paths();
	QString DefaultFile = mod_file;
	QFile fin(DefaultFile);
	if (fin.open(QIODevice::WriteOnly)==false)
		return;
	QTextStream st(&fin);
	QDir dir(QCoreApplication::applicationDirPath());
	foreach (QString sf, s) {
		QString strRelPath;
		if (QDir::isAbsolutePath(sf)==true)
			strRelPath  =  dir.relativeFilePath(sf);
		else
			strRelPath = sf;
		if (strRelPath.length()>0 && strRelPath.length()<sf.length())
			st<<strRelPath<<"\n";
		else
			st<<sf<<"\n";
	}

	fin.close();
}

void taskBusPlatformFrm::load_mod_def(QString mod_file)
{
	QString DefaultFile = mod_file;
	QFile fin(DefaultFile);
	if (fin.open(QIODevice::ReadOnly)==false)
	{
		QThread::msleep(2000);
		emit hideSplash();
		return;
	}
	QTextStream st(&fin);
	QStringList lstNames;
	while (st.atEnd()==false)
	{
		lstNames<< st.readLine();
	}
	fin.close();
	m_pTrayIcon->showMessage(tr("Init Modules..."),tr("Init modules from default_mods.text"),QSystemTrayIcon::Information, 1000);
	load_modules(lstNames);
	m_pTrayIcon->showMessage(tr("Succeed."),tr("Init modules from default_mods.text succeed!"),QSystemTrayIcon::Information, 2000);
	QThread::msleep(1000);
	emit hideSplash();
	QFileInfo info (mod_file);
	ui->label_defaultMod->setText(info.completeBaseName());
}


void taskBusPlatformFrm::on_toolButton_ModDel_clicked()
{
	if (QMessageBox::Ok!=QMessageBox::warning(this,tr("Remove All modules"),tr("This approach will clear current mod file."),QMessageBox::Ok|QMessageBox::Cancel))
		return;
	refModule()->clear();
	ui->listView_modules->setModel(0);
	m_pClassModel->clear();
	m_pClassModel->appendRow(new QStandardItem(tr("All")));
	m_toolModules.clear();
	m_toolModules[tr("All")] = m_pRefModule = new taskModule(true,this);
	ui->listView_modules->setModel(m_pRefModule);
}


void taskBusPlatformFrm::on_toolButton_modSave_clicked()
{
	QSettings settings(inifile(),QSettings::IniFormat);
	QString strLastSaveDir = settings.value("history/strLastDefDir","./").toString();
	QString newfms = QFileDialog::getSaveFileName(this,tr("save mod_def file as"),strLastSaveDir,
													   "text files (*.text);;All files(*.*)"
													   );

	if (newfms.size()>0)
	{
		QFileInfo info(newfms);
		QDir dir(QCoreApplication::applicationDirPath());
		QString pts = info.absolutePath();
		QString strl = dir.relativeFilePath(pts);
		if (strl.length() < pts.length())
			pts = strl;
		settings.setValue("history/strLastDefDir",pts);
		//Save
		save_mod_def(newfms);
		QString relp = dir.relativeFilePath(newfms);
		if (relp.length()<=newfms.length())
			newfms = relp;
		settings.setValue("current/mod_def",newfms);
		ui->label_defaultMod->setText(info.completeBaseName());
	}
}


void taskBusPlatformFrm::on_toolButton_ModLoad_clicked()
{
	QSettings settings(inifile(),QSettings::IniFormat);
	QString strLastSaveDir = settings.value("history/strLastDefDir","./").toString();
	QString newfms = QFileDialog::getOpenFileName(this,tr("save mod_def file as"),strLastSaveDir,
												  "text files (*.text);;All files(*.*)"
												  );

	if (newfms.size()>0)
	{
		refModule()->clear();
		ui->listView_modules->setModel(0);
		m_pClassModel->clear();
		m_pClassModel->appendRow(new QStandardItem(tr("All")));
		m_toolModules.clear();
		m_toolModules[tr("All")] = m_pRefModule = new taskModule(true,this);
		ui->listView_modules->setModel(m_pRefModule);
		//Load
		load_mod_def(newfms);

		QFileInfo info(newfms);
		QDir dir(QCoreApplication::applicationDirPath());
		QString relp = dir.relativeFilePath(newfms);
		if (relp.length()<=newfms.length())
			newfms = relp;
		settings.setValue("current/mod_def",newfms);
		ui->label_defaultMod->setText(info.completeBaseName());

	}
}
